﻿//-------------------------------------------------------------------------
///-----------------mqtt_client--------------------------------------------
///-----------------mqtt客户端---------------------------------------------
///-----------------2022/3/28---by mky.蒙克雨------------------------------
//------------------------------------------------------------------------- 
#pragma once

//-------------------------------------------------------------------------
#ifndef __MQTT_CLIENT_H__
#define __MQTT_CLIENT_H__

//-------------------------------------------------------------------------
#include <iostream> 
#include <memory>
#include "ftmqtt.h"

//-------------------------------------------------------------------------
namespace mky {

	//-------------------------------------------------------------------------
	using namespace std;
	enum QOS_MQTT_E {
		QOS_ONCE_MOST = 0,/**< QOS0:至多1次,可能丢失 */
		QOS_ONCE_LEAST,	/**< QOS1:至少1次,确保到达,可能重复 */
		QOS_ONCE_ONLY	/**< QOS2:只有1次,确保到达,没有重复 */
	};

	//-------------------------------------------------------------------------
	/** 定义类名(给类添加获取类名的方法) */
	#define DECL_CLASSNAME(ClassName)	public:virtual std::string& className(){return this->__CLASS_NAME__;}private:std::string __CLASS_NAME__{#ClassName};
	#define CSTR(stdstr) ((stdstr).c_str())

	//-------------------------------------------------------------------------
	class MqttClientProxy {
		DECL_CLASSNAME("MqttClientProxy")
		using MqttMsgHandler = void(*)(void*, std::string, std::string);
	public:
		MqttClientProxy() {}
		~MqttClientProxy() {}
		/**
		 * @brief 默认的接收消息方法
		 * @param topic 消息主题
		 * @param msg 	消息内容
		 */
		virtual void onRecvMsg(void*, std::string topic, std::string recv_message) {
			printf("receive topic: %s, size(%d), msg[%s]\n", CSTR(topic), (int)recv_message.size(), CSTR(recv_message));
		}
	protected:
		//bool initMqttClient(std::string cfg);
		int keepAlive() {
			return mv_mqtt_keep();
		}
		//bool setWillOption(const std::string& topic, const std::string& msg, int qos, bool retained){};
		int open(std::string cfg,MqttMsgHandler handler){
			//if (instance != nullptr){
			//	return true;
			//}
			instance = mv_mqtt_create_instance();
			if (instance == nullptr){
				printf("mqtt open error!\n");
				return false;
			}
			mv_mqtt_init_instance(instance, cfg, handler);
			return true;
		}
		int connect() {
			return mv_mqtt_connect(instance);
		}
		int subscribe(const std::string& topic, int qos){
			return mv_mqtt_subscribe(instance, topic, qos);
		}
		int publish(const std::string& topic, const std::string& msg, int qos) {
			return mv_mqtt_publish(instance, topic, msg, qos);
		}
		int unsubscribe(const std::string& topic) {
			return mv_mqtt_unsubscribe(instance, topic);
		}
		int disconnect() {
			return mv_mqtt_disconnect(instance, 5);
		}
		int close() {
			mv_mqtt_close(instance);
			instance = nullptr;
			return 0;
		}
		mv_mqtt_instance_t getMqttInstance() {
			if (instance == nullptr)
				return nullptr;
			return instance;
		}
	private:
		mv_mqtt_instance_t instance;
	};

	//-------------------------------------------------------------------------
	class MqttClientProxy;
	template <class T>
	/* MqttClientAdapter是一个单例模板类,可以使用DECL_INSTANCE宏 */
	class MqttClientAdapter :public MqttClientProxy {
		DECL_CLASSNAME(MqttClientAdapter)
	public:
		static T& getInstance(){
			static T instance;
			return instance;
		}
		virtual ~MqttClientAdapter() {};
		/**
		 * @brief 保持心跳
		 * @return true 执行成功
		 * @return false 执行失败
		 */
		int keepAlive(){
			return MqttClientProxy::keepAlive();
		}
		/**
		 * @brief 设置遗言
		 * @param topic 遗愿主题
		 * @param msg 遗愿消息
		 * @param qos 遗愿qos
		 * @param retained 是否保存
		 * @return true 设置成功
		 * @return false 设置失败
		 */
		int setWillOption(const std::string& topic, const std::string& msg, int qos, bool retained){
			return false;
		}
		/**
		 * @brief 打开客户端
		 * @param cfg 配置文件
		 * @return true 打开成功
		 * @return false 打开失败
		 */
		int open(std::string cfg){
			return MqttClientProxy::open(cfg, &(handleMessage));
		}
		/**
		 * @brief 连接代理服务器
		 * @return true 连接成功
		 * @return false 连接失败
		 */
		int connect(){
			return MqttClientProxy::connect();
		}
		/**
		 * @brief 订阅消息
		 * @param topic 消息主题
		 * @param qos 服务质量
		 * @return true 订阅成功
		 * @return false 订阅失败
		 */
		int subscribe(const std::string& topic, int qos){
			return MqttClientProxy::subscribe(topic, qos);
		}
		/**
		 * @brief 发布消息
		 * @param topic 消息主题
		 * @param msg 消息内容
		 * @param qos 服务质量
		 * @return true 发布成功
		 * @return false 发布失败
		 */
		int publish(const std::string& topic, const std::string& msg, int qos){
			return MqttClientProxy::publish(topic, msg, qos);
		}
		/**
		 * @brief 取消订阅
		 * @param topic 消息主题
		 * @return true 取消订阅成功
		 * @return false 取消订阅失败
		 */
		int unsubscribe(const std::string& topic){
			return MqttClientProxy::unsubscribe(topic);
		}
		/**
		 * @brief 断开与代理服务器的连接
		 * @return true 断开连接成功
		 * @return false 断开连接失败
		 */
		int disconnect(){
			return MqttClientProxy::disconnect();
		}
		/**
		 * @brief 关闭客户端
		 * @return true 关闭成功
		 * @return false 关闭失败
		 */
		int close(){
			return MqttClientProxy::close();
		}
		mv_mqtt_instance_t getMqttInstance() {
			return  MqttClientProxy::getMqttInstance();
		}
	private:
		static void handleMessage(void* client, std::string topic, std::string recv_message)
		{
			getInstance().onRecvMsg(client,topic,recv_message);
		}
	protected:
		MqttClientAdapter() {};
		MqttClientAdapter(const MqttClientAdapter&) = delete;
		MqttClientAdapter& operator=(const MqttClientAdapter&) = delete;
	};

	//-------------------------------------------------------------------------
	/* MqttClient是一个mqtt客户端 */
	//-------------------------------------------------------------------------
	template <class T>
	class MqttClient : public MqttClientAdapter<T>
	{
	public:
		MqttClient() : MqttClientAdapter<T>() {};
		MqttClient(const MqttClient&) = delete;
		MqttClient& operator=(const MqttClient&) = delete;
	};

	//-------------------------------------------------------------------------
}

//-------------------------------------------------------------------------
#endif //!__MQTT_CLIENT_H__
